package jgrit.control;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Is capable of rewriting a C source file so that it compiles
 * correctly under GCC with the '-pedantic' and '-ansi' options.
 * <p>
 * This means that:
 * <ul>
 * <li>C++ style comments (//) are rewritten as C style comments (/*)
 * <li>a newline is inserted at the end of the file if it isn't already there
 * </ul>
 * <p>
 * NOTE: This postprocessing will interfere with the
 *       'Append (or Replace Existing Section)' option.
 * 
 * @author Sam Hartsfield
 * @author Taylor Perkins
 * @author David Foster
 */
public class PedanticProcessing {
	
	/**
	 * The column after which the C89-style comment should be terminated
	 */
	private static int COMMENT_CLOSE_COL = 72;

	/**
	 * Replace C++-style comments with C89-style comments to allow the files
	 * to compile with the "-ansi" and "-pedantic" gcc options.
	 * 
	 * @param file The file to process
	 * @throws IOException Thrown if there is a problem with the file
	 */
	public static void postProcessFile(File file) throws IOException {
		BufferedReader reader = new BufferedReader(new FileReader(file));
		List<String> output = new ArrayList<String>();
		String line;
		
		// Read in a line, and convert the comments if necessary.
		while ((line = reader.readLine()) != null)
		{			
			int commentStart;
			if ((commentStart = line.indexOf("//")) != -1) {
				int spaces = Math.max(0, COMMENT_CLOSE_COL - line.length());
				
//				int contentLength = line.length() - (commentStart + 2);
//				System.out.println(commentStart + " + " + "/*" + " + "
//						+ contentLength + " + " + spaces + " + " + "*/" + " = "
//						+ (commentStart + 2 + contentLength + spaces + 2));
				
				line = line.substring(0, commentStart) + "/*"
						+ line.substring(commentStart + 2, line.length());
				
				for (int i = 0; i < spaces; i++) {
					line += ' ';
				}
				
				line += "*/";
				
				/*
				 * Replace tabs (only in comment blocks) with a single space
				 * so that the end comments line up
				 */
				line = line.replace('\t', ' ');
			}
			output.add(line);
		}
		
		reader.close();
		BufferedWriter writer = new BufferedWriter(new FileWriter(file));
		
		// Write the output to the file.
		// TODO: Account for windows carriage returns?
		for (int i = 0; i < output.size(); i++) {
			writer.write(output.get(i) + "\n");
		}
		
		// Close streams.
		writer.close();
	}
	
	/**
	 * Given a file, converts the comments back from "/*" style, to "//" style.
	 * This is needed in order to allow for appending to a file.
	 * @param file
	 * @throws IOException
	 */
	public static void preProcessFile(File file) throws IOException {
		BufferedReader reader = new BufferedReader(new FileReader(file));
		List<String> output = new ArrayList<String>();
		BufferedWriter writer = new BufferedWriter(new FileWriter(file));
		String line;
		
		// Read in a line, and convert the comments if necessary.
		while ((line = reader.readLine()) != null)
		{
			// NOTE: There is one line in the header file that this won't work,
			// but since it doesn't affect the block line the append option
			// uses, it actually does not mess up the output.
			if (line.startsWith("/*") && line.endsWith("*/")) {
				// Remove old comments, and add new ones
				line = "// " + line.substring(2, line.length() - 3);
			}
			output.add(line);
		}
		
		// Write the output to the file.
		// TODO: Account for windows carriage returns.
		for (int i = 0; i < output.size(); i++) {
			writer.write(output.get(i) + "\n");
		}
		
		// Close streams.
		reader.close();
		writer.close();
	}
}
